package com.yifeng.repo.base.utils.redis.worker;

import com.google.common.collect.Lists;
import com.yifeng.repo.base.utils.redis.client.AbstractJedisCommand;
import com.yifeng.repo.base.utils.redis.client.JedisClient;
import redis.clients.jedis.GeoCoordinate;
import redis.clients.jedis.GeoRadiusResponse;
import redis.clients.jedis.GeoUnit;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.GeoAddParams;
import redis.clients.jedis.params.GeoRadiusParam;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 注意：redis 3.2和以上版本才支持Geo功能
 * Created by daibing on 2024/1/10.
 */
public class RedisGeoWorker {
    private final JedisClient jedisClient;

    public RedisGeoWorker(JedisClient jedisClient) {
        this.jedisClient = jedisClient;
    }

    /**
     * 增加成员
     * @param key 建议按照省份来划分数据范围
     * @param longitude 指定经度
     * @param latitude 指定维度
     * @param member 可以是人员编号，也可以是门店编号
     */
    public Long geoAdd(String key, double longitude, double latitude, String member) {
        return this.geoAdd(key, Collections.singletonMap(member, new GeoCoordinate(longitude, latitude)));
    }

    /**
     * 批量增加成员
     * @param key 建议按照省份来划分数据范围
     * @param memberCoordinateMap 成员到坐标的映射关系
     * @return 返回变更条数
     */
    public Long geoAdd(String key, Map<String, GeoCoordinate> memberCoordinateMap) {
        GeoAddParams params = GeoAddParams.geoAddParams().ch();
        return new AbstractJedisCommand<Long>() {
            @Override
            protected Long doRun(Jedis jedis) {
                return jedis.geoadd(key, params, memberCoordinateMap);
            }
        }.doExecute(jedisClient);
    }

    /**
     * 删除成员列表（删除所有member后，key也将自动删除）
     */
    public Long geoRemove(String key, List<String> members) {
        return new AbstractJedisCommand<Long>() {
            @Override
            protected Long doRun(Jedis jedis) {
                return jedis.zrem(key, members.toArray(new String[0]));
            }
        }.doExecute(jedisClient);
    }

    /**
     * 删除成员
     */
    public Long geoRemove(String key, String member) {
        return this.geoRemove(key, Lists.newArrayList(member));
    }

    /**
     * 统计成员个数
     */
    public Long geoTotal(String key) {
        return new AbstractJedisCommand<Long>() {
            @Override
            protected Long doRun(Jedis jedis) {
                return jedis.zcard(key);
            }
        }.doExecute(jedisClient);
    }

    /**
     * 统计成员个数
     */
    public Set<String> geoMembers(String key) {
        return new AbstractJedisCommand<Set<String>>() {
            @Override
            protected Set<String> doRun(Jedis jedis) {
                return jedis.zrange(key, 0, -1);
            }
        }.doExecute(jedisClient);
    }

    /**
     * 获取成员列表的坐标
     */
    public List<GeoCoordinate> geoPos(String key, List<String> members) {
        return new AbstractJedisCommand<List<GeoCoordinate>>() {
            @Override
            protected List<GeoCoordinate> doRun(Jedis jedis) {
                return jedis.geopos(key, members.toArray(new String[0]));
            }
        }.doExecute(jedisClient);
    }

    /**
     * 获取成员的坐标
     */
    public GeoCoordinate geoPos(String key, String member) {
        List<GeoCoordinate> geoCoordinates = this.geoPos(key, Lists.newArrayList(member));
        if (geoCoordinates.isEmpty()) {
            return null;
        }
        return geoCoordinates.get(0);
    }

    /**
     * 按照指定经纬度来查找周边成员
     * @param key 建议按照省份来划分数据范围
     * @param longitude 指定经度
     * @param latitude 指定维度
     * @param radiusMeter 半径，单位米
     * @param count 查找数量
     * @return 成员数据列表
     */
    public List<GeoRadiusResponse> geoRadius(String key, double longitude, double latitude, double radiusMeter, int count) {
        GeoRadiusParam param = GeoRadiusParam.geoRadiusParam()
                .withCoord()
                .withDist()
                /*.withHash()*/
                .count(count)
                .sortAscending();
        return new AbstractJedisCommand<List<GeoRadiusResponse>>() {
            @Override
            protected List<GeoRadiusResponse> doRun(Jedis jedis) {
                return jedis.georadius(key, longitude, latitude, radiusMeter, GeoUnit.M, param);
            }
        }.doExecute(jedisClient);
    }

    /**
     * 按照指定成员来查找周边成员
     * @param key 建议按照省份来划分数据范围
     * @param member 可以是人员编号，也可以是门店编号
     * @param radiusMeter 半径，单位米
     * @param count 查找数量
     * @return 成员数据列表
     */
    public List<GeoRadiusResponse> geoRadius(String key, String member, double radiusMeter, int count) {
        GeoRadiusParam param = GeoRadiusParam.geoRadiusParam()
                .withCoord()
                .withDist()
                /*.withHash()*/
                .count(count)
                .sortAscending();
        return new AbstractJedisCommand<List<GeoRadiusResponse>>() {
            @Override
            protected List<GeoRadiusResponse> doRun(Jedis jedis) {
                return jedis.georadiusByMember(key, member, radiusMeter, GeoUnit.M, param);
            }
        }.doExecute(jedisClient);
    }
}
